/**
1000ms并不是定时器执行前的等待时间，而是将定时器中的回调函数加入任务队列前的等待时间。   
*/
let func1 = () => {
  setTimeout(() => {
    console.log('1')
  }, 1000)
  setTimeout(() => {
    console.log('1')
  }, 1000)
}

let func2 = () => {
  for (var i = 0; i < 5; i++) {
    setTimeout(() => {
      console.log(i)
    }, 1000)
  }
}
/**
 * 定时器异步执行的只是定时器中的回调函数，
 * 定时器的时间可不会异步，
 * 这里只是将固定的时间换成了一个简单乘法计算而已，所以时间计算在运行到定时器时就已经同步计算完毕了
 */
let func3 = () => {
  for (var i = 0; i < 5; i++) {
    setTimeout(() => {
      console.log(i)
    }, 1000 * i)
  }
}
/** 请以题目三为原型做出修改，让for循环先输出0之后每隔一秒依次输出1，2，3，4。
 *
 * 1 利用一个自执行函数包裹了定时器，而定时器中的回调函数引用了外层自调函数的形参 i ，所以此时定时器的回调函数是一个闭包。
 * 有趣的事情来了，当创建每个自执行函数时变量 i 都会作为参数立刻传入到自执行函数体内，
 * 此时 i 已经和函数作用域绑定到了一起，而定时器回调函数引用了外层函数的 i ，这样就达到我们想要的目的了
 *
 * 定时器是异步，它应该最后执行，但JS采用的是静态作用域，函数在定义时，它的作用域就已经被确定了，不管它在何处被调用，
 * 它能访问的外层作用域就是被创建时所在的作用域，
 * 虽然定时器的回调看着是最后执行，但它在执行时由于自己没有 i ，所以只能从父级作用域找，而它的父级就是创建它的自执行函数。
 */
let func4 = () => {
  for (var i = 0; i < 5; i++) {
    ;(function (i) {
      setTimeout(() => {
        console.log(i)
      }, 1000 * i)
    })(i)
  }
}

/**2 利用按值传递特性
 * 当基本类型的数据作为函数参数时总是按值传递，就像额外拷贝了一份进去，而引用类型的数据传递的其实是一个引用地址，任何操作都会修改原有的数据。
 */
function fn(i) {
  setTimeout(() => {
    console.log(i)
  }, 1000 * i)
}
let func5 = () => {
  for (var i = 0; i < 5; i++) {
    fn(i)
  }
}

/**3 利用ES6的let
 * 当for循环中使用let去声明变量 i 时，利用块级作用域的特性，让每次循环的 i 成为独立的一份
 */
let func6 = () => {
  for (let i = 0; i < 5; i++) {
    setTimeout(() => {
      console.log(i)
    }, 1000 * i)
  }
}

/**4 可以使用定时器第三参数
 * 当for循环中使用let去声明变量 i 时，利用块级作用域的特性，让每次循环的 i 成为独立的一份
 */
let func7 = () => {
  for (let i = 0; i < 5; i++) {
    setTimeout(
      () => {
        console.log(i)
      },
      1000 * i,
      i
    )
  }
}

/* 
* 定时器的第一参数由一个普通的回调函数变成了一个自执行函数
* 是无等待的同时输出0，1，2，3，4。说到这可能有同学就有疑问了，输出0-4也就算了，为何输出之间还没间隔了。
* 难道不是把五个自执行函数压入任务队列，然后先输出0后每隔一秒一次输出吗。
* 
* 运行到定时器时，直接将第一参数的函数给执行了，定时器的时间直接不会起作用了
* 几乎无等待的输出1，尽管这是一个周期性定时器，但之后都不会再执行了，因为第一参数不是一个合格的回调函数
*/
let func8 = () => {
  for (var i = 0; i < 5; i++) {
    setTimeout((function () {
      console.log(i)
    })(i), 1000 * i)
  }
}

let func9 = () => {
  for (var i = 0; i < 5; i++) {
    setTimeout(fn(), 1000 * i)
  }
}
